from flask import request, jsonify, g, current_app

from apps.apis import api
from apps.core.auth import verify_json_schema, verify_token_auth
from apps.core.database import db
from apps.core.schemaall import user_schema, token_schema, user_change_schema
from apps.models import User
from apps.utils.return_info import ReturnInfo


@api.route("/user/login", methods=['POST'])
@verify_json_schema(user_schema)
# @func_line_time
def login():
    """
    登录接口
    ---
    tags:
      - user
    parameters:
      - in: body
        name: body
        required: true
        description: JSON 参数.
        schema:
          id: users
          properties:
            username:
              type: string
              description: 用户名.
              example: Alice
            passwd:
              type: string
              description: 密码.
              example: Smith123
    consumes:
      - application/json
    produces:
      - application/json
    definitions:
      ReturnInfoLogin:
        type: object
        properties:
          msg_code:
            type: string
            description: SUCCESS 或者 FAILED.
            example: SUCCESS
          msg:
            type: string
            description: 说明文字，帮助找到失败原因
            example: 不能使用get请求
          data:
            type: object
            description: 返回的信息全部在data中获取
            properties:
              result:
                $ref: '#/definitions/Login'

      Login:
        type: object
        properties:
          token:
            type: string
            description: token值
            example: fdsf...
          is_admin:
            type: integer
            description: 1 or 0 ,1代表admin用户 0代表普通用户
            example: 1

      User:
        type: object
        properties:
          username:
            type: string
            description: 用户名.
            example: Alice
          passwd:
            type: string
            description: 密码.
            example: Smith123
          ipaddr:
            type: string
            description: ip地址.
            example: 192.168.31.127
    responses:
      200:
        description: OK.
        schema:
          $ref: '#/definitions/ReturnInfoLogin'
        examples:
          returninfo: {"msg_code":"SUCCESS","msg":"成功","data":{"result": {"is_admin": 1,"token":"eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg"}}}
      400:
        description: 上传数据有不符合规则,data中放入的是上传的数据.
        examples:
          returninfo: {"msg_code":"FAILED","msg":"参数至少一个为空","data":{"ipaddr": "192.168.31.127","passwd": "","username": "Alice"}}
      405:
        description: 请求方式错误

    """
    ret_obj = ReturnInfo()
    jsons = request.json
    username = jsons.get("username")
    passwd = jsons.get("passwd")
    ret_obj.msg_code = "FAILED"
    user = User.query.filter_by(username=username, is_acitve=1).first()
    if not user or not user.verify_password(passwd):
        ret_obj.msg = "用户不存在或密码错误"
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())
    else:
        token = user.generate_auth_token()
        token = token
        ret_obj.msg_code = "SUCCESS"
        ret_obj.msg = "成功"
        is_admin = 0
        if user.is_admin(current_app.config.get("ADMIN_USER")):
            is_admin = 1
        ret_obj.data = {"result": {"token": token, "is_admin": is_admin}}
    return jsonify(ret_obj.todict())


@api.route("/user/newtoken", methods=['POST'])
@verify_json_schema(token_schema)
@verify_token_auth(allowtokennull=False)
def newtoken():
    """
    获取新的token
    ---
    tags:
      - user
    parameters:
      - in: body
        name: body
        required: true
        description: JSON 参数.
        schema:
          id: token
          properties:
            token:
              type: string
              description: token.
              example: eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg
    consumes:
      - application/json
    produces:
      - application/json
    definitions:
      ReturnInfoToken:
        type: object
        properties:
          msg_code:
            type: string
            description: SUCCESS 或者 FAILED.
            example: SUCCESS
          msg:
            type: string
            description: 说明文字，帮助找到失败原因
            example: 不能使用get请求
          data:
            type: object
            description: 返回的信息全部在data中获取
            properties:
              result:
                $ref: '#/definitions/Token'

      Token:
        type: object
        properties:
          token:
            type: string
            description: token值
            example: fdsf...
    responses:
      200:
        description: OK.
        schema:
          $ref: '#/definitions/ReturnInfoToken'
        examples:
          returninfo: {"msg_code":"SUCCESS","msg":"成功","data":{"result": {"token":"eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg"}}}
      400:
        description: 上传数据有不符合规则,data中放入的是上传的数据.
        examples:
          returninfo: {"msg_code":"FAILED","msg":"参数至少一个为空","data":{"ipaddr": "192.168.31.127","passwd": "","username": "Alice"}}
      405:
        description: 请求方式错误

    """
    ret_obj = ReturnInfo()
    ret_obj.msg_code = "SUCCESS"
    ret_obj.msg = "获取新的token"
    token = g.user.generate_auth_token()
    ret_obj.data = {"result": {"token": token}}
    return jsonify(ret_obj.todict())


@api.route("/user/verify_token", methods=['POST'])
@verify_json_schema(token_schema)
@verify_token_auth(allowtokennull=False)
def verify_token():
    """
    测试你获取的token是否有效
    ---
    tags:
      - user
    parameters:
      - in: body
        name: body
        required: true
        description: JSON 参数.
        schema:
          id: token
          properties:
            token:
              type: string
              description: token.
              example: eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg
    consumes:
      - application/json
    produces:
      - application/json
    definitions:
      ReturnInfo:
        type: object
        properties:
          msg_code:
            type: string
            description: SUCCESS 或者 FAILED.
            example: SUCCESS
          msg:
            type: string
            description: 说明文字，帮助找到失败原因
            example: 不能使用get请求
          data:
            type: string
            description: 返回的信息全部在data中获取
            example:

    responses:
      200:
        description: OK.
        schema:
          $ref: '#/definitions/ReturnInfo'
        examples:
          returninfo: {"msg_code":"SUCCESS","msg":"成功","data":""}
      400:
        examples:
          returninfo: {"msg_code":"FAILED","msg":"token为空","data":""}
      405:
        description: 请求方式错误

    """
    ret_obj = ReturnInfo()
    ret_obj.msg_code = "SUCCESS"
    ret_obj.msg = "token 认证成功"
    return jsonify(ret_obj.todict())


@api.route("/user/change_password", methods=['POST'])
@verify_json_schema(user_change_schema)
def change_password():
    """
     修改密码
    ---
    tags:
      - user
    parameters:
      - in: body
        name: body
        required: true
        description: JSON 参数.
        schema:
          id: change_password
          properties:
            username:
              type: string
              description: 用户名.
              example: Alice
            old_pwd:
              type: string
              description: 旧密码.
              example: '123456'
            new_pwd:
              type: string
              description: 新密码.
              example: '123456'
            retype_new_pwd:
              type: string
              description: 新密码.第二次输入的新密码，后台会验证两次密码是否一致
              example: '123456'
    consumes:
      - application/json
    produces:
      - application/json
    definitions:
      ReturnInfo:
        type: object
        properties:
          msg_code:
            type: string
            description: SUCCESS 或者 FAILED.
            example: SUCCESS
          msg:
            type: string
            description: 说明文字，帮助找到失败原因
            example: 不能使用get请求
          data:
            type: string
            description: 返回的信息全部在data中获取
            example:
    responses:
      200:
        description: OK.
        schema:
          $ref: '#/definitions/ReturnInfo'
        examples:
          returninfo: {"msg_code":"SUCCESS","msg":"成功","data":""}
      400:
        examples:
          returninfo: {"msg_code":"FAILED","msg":"token为空","data":""}
      405:
        description: 请求方式错误
    :return:
    """
    ret_obj = ReturnInfo()
    jsons = request.json
    username = jsons.get("username")
    old_pwd = jsons.get("old_pwd")
    new_pwd = jsons.get("new_pwd")
    retype_new_pwd = jsons.get("retype_new_pwd")

    user = User.query.filter_by(username=username).first()
    if not user or not user.verify_password(old_pwd):
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "用户不存在或原始密码错误"
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())
    if new_pwd and new_pwd == retype_new_pwd:
        if not user.passwd_rule(new_pwd):
            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "密码不符合规则，必须包含数字、字母和一个特殊符号! @ # $ % ^ * ( ) ~ `{ } [ ] | & _"
            ret_obj.data = {"result": {"username": username}}
            return jsonify(ret_obj.todict())
        user.hash_password(new_pwd)
        try:
            db.session.add(user)
            db.session.commit()
        except Exception as e:
            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "无法插入数据库"
            ret_obj.data = {"errmsg": str(e)}
            return jsonify(ret_obj.todict())
        ret_obj.msg_code = "SUCCESS"
        ret_obj.msg = "修改密码成功"
        ret_obj.data = {"result": {"username": username}}

    else:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "新密码为空或者两次输入不一致"
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())
    return jsonify(ret_obj.todict())
